package com.g.ocache;

import java.util.List;
import java.util.Map;

import com.g.ocache.event.CacheEventListener;
import com.g.ocache.event.CacheEventPublisher;
import com.g.ocache.index.Index;


/**
 * Cache is the central interface. Caches are managed by the {@link CacheManager}.
 * The Cache performs logical actions. It delegates physical implementations to
 * its {@link Store}s.
 * <p/>
 * There are {@link Index}s for many non-pk and range query.
 * <p/>
 * {@link CacheInitializer} for the cache initialize in the {@link CacheManager}.
 * <p/>
 * If no value was found with a key in the cache. Cache will load it from the {@link CacheLoader}.
 * <p/>
 * {@link CacheStatistics} on cache usage are collected and made available through public methods.
 * <p/>
 * {@link CacheEventListener} for receive the event from the cache operation.
 * 
 * @author Jingqi Xu
 */
public interface Cache<K, V> {
	
	/**
	 * Whether or not the cache is started.
	 * 
	 * @return true if the cache has been started.
	 */
	boolean isRunning();
	
	/**
	 * Start the cache.
	 * 
	 * @throws Exception
	 */
	void start() throws Exception;
	
	/**
	 * Stop the cache.
	 * 
	 * @throws Exception
	 */
	void stop() throws Exception;
	
	/**
	 * Gets the size of the cache. This size is the actual size of entries,
	 * including expired entries that have not been removed.
	 * 
	 * @return The size of the cache.
	 */
	int size();
	
	/**
	 * Check cache to see if the key exists in the cache.
	 * 
	 * @param key the key to check for
	 * @return true if the cache contains the key.
	 */
	boolean containsKey(K key);
	
	/**
	 * Clear all cached entries.
	 */
	void clear();
	
	/**
     * Removes an entry from the Cache. This also removes it from any
     * stores and index it may be in.
     * <p/>
     * Also notifies the CacheEventListener after the entry was removed,
     * but only if an entry with the key actually existed.
     * 
	 * @param key
	 * @return true if the entry was removed, false if it was not found in the cache.
	 */
	V remove(K key);
	
	/**
	 * Gets an value from the cache.
	 * 
	 * @param key
	 * @return the value to which this map maps the specified key, or null, if it does not exist.
	 */
	V get(K key);
	
	/**
	 * Gets all of the values from the cache.
	 * 
	 * @return all values in the cache.
	 */
	Map<K, V> getAll();
	
	/**
	 * Put an entry in the cache.
	 * 
	 * @param key key with which the specified value is to be associated
	 * @param value value to be associated with the specified key
	 * @return the previous value associated with the specified key, or
     *         <tt>null</tt> if there was no mapping for the key.
	 * @throws ValidationException if there is a validator was set to the cache and
	 *         the value which being put in the cache is older then the value which
	 *         is already in the cache.
	 */
	V put(K key, V value);
	
	/**
     * If the specified key is not already associated
     * with a value, associate it with the given value.
     * This is equivalent to
     * <pre>
     *   if (!cache.containsKey(key))
     *       return cache.put(key, value);
     *   else
     *       return cache.get(key);</pre>
     * 
	 * @param key key with which the specified value is to be associated
	 * @param value value to be associated with the specified key
	 * @return the previous value associated with the specified key, or
     *         <tt>null</tt> if there was no mapping for the key.
	 * @throws ValidationException if there is a validator was set to the cache and
	 *         the value which being put in the cache is older then the value which
	 *         is already in the cache.
	 */
	V putIfAbsent(K key, V value);
	
	/**
	 * Put all mappings from the key to the value <tt>v</tt> in the
     * specified map.
     * 
	 * @param values mappings to be stored in this cache.
	 * @return the previous value associated with the specified keys, or
     *         <tt>null</tt> if there was no mapping for the key.
	 */
	Map<K, V> putAll(Map<K, V> values);
	
	/**
	 * Get the name of the cache.
	 * @return name
	 */
	Object getName();
	
	/**
	 * Get all of the indices that was set to the cache.
	 * @return indices
	 */
	List<Index<K, V>> getIndices();
	
	/**
	 * Get the index which with the specified name.
	 * @param name the name of the index.
	 * @return index
	 */
	Index<K, V> getIndex(String name);
	
	/**
	 * Add an index to the cache.
	 * @param index
	 * @return true if this cache did not already contain the specified
     *         index
	 */
	boolean addIndex(Index<K, V> index);
	
	/**
	 * Get the <tt>CacheInitializer</tt>
	 * @return CacheInitializer
	 */
	CacheInitializer<K, V> getInitializer();
	
	/**
	 * Get the <tt>CacheEventPublisher</tt>
	 * @return CacheEventPublisher
	 */
	CacheEventPublisher<K, V> getPublisher();
	
	/**
	 * Get the <tt>CacheLoader</tt>
	 * @return CacheLoader
	 */
	CacheLoader<K, V> getLoader();
	
	/**
	 * Set the <tt>CacheLoader</tt>
	 * @param loader
	 */
	void setLoader(CacheLoader<K, V> loader);
	
	/**
	 * Get the <tt>CacheValidator</tt>
	 * @return CacheValidator
	 */
	CacheValidator<K, V> getValidator();
	
	/**
	 * Set the <tt>CacheValidator</tt>
	 * @param validator
	 */
	void setValidator(CacheValidator<K, V> validator);
	
	/**
	 * Get the <tt>CacheStatistics</tt>
	 * @return CacheStatistics
	 */
	CacheStatistics<K, V> getStatistics();
	
	/**
	 * Set the <tt>CacheStatistics</tt>
	 * @param statistics
	 */
	void setStatistics(CacheStatistics<K, V> statistics);
	
	/**
	 * Add the <tt>CacheEventListener</tt>
	 * @param listener
	 * @return true if there is a <tt>CacheEventPublisher</tt> set to the cache.
	 *         false if have no <tt>CacheEventPublisher</tt> for the cache.
	 */
	boolean addCacheEventListener(CacheEventListener<K, V> listener);
	
	/**
	 * Remove the <tt>CacheEventListener</tt>
	 * @param listener
	 * @return true if there is a <tt>CacheEventPublisher</tt> set to the cache.
	 *         false if have no <tt>CacheEventPublisher</tt> for the cache.
	 */
	boolean removeCacheEventListener(CacheEventListener<K, V> listener);
	
	/**
	 * The cache factory for the {@link CacheManager} to create cache instance.
	 * <p/>
	 * Strongly recommand that config all the components that you need in the
	 * factory implementation.
	 */
	interface Factory<K, V> {
		
		Cache<K, V> create(Object id);
	}
}
